package image;

import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * GENERAL FILE FORMAT
 * <p>
 * +-----------------------+
 * <p>
 * | +-------------------+ |
 * <p>
 * | |   GIF Signature   | |
 * <p>
 * | +-------------------+ |
 * <p>
 * | +-------------------+ |
 * <p>
 * | | Screen Descriptor | |
 * <p>
 * | +-------------------+ |
 * <p>
 * | +-------------------+ |
 * <p>
 * | | Global Color Map  | |
 * <p>
 * | +-------------------+ |
 * <p>
 * . . .               . . .
 * <p>
 * | +-------------------+ |    ---+
 * <p>
 * | |  Image Descriptor | |       |
 * <p>
 * | +-------------------+ |       |
 * <p>
 * | +-------------------+ |       |
 * <p>
 * | |  Local Color Map  | |       |-   Repeated 1 to n times
 * <p>
 * | +-------------------+ |       |
 * <p>
 * | +-------------------+ |       |
 * <p>
 * | |    Raster Data    | |       |
 * <p>
 * | +-------------------+ |    ---+
 * <p>
 * . . .               . . .
 * <p>
 * |-    GIF Terminator   -|
 * <p>
 * +-----------------------+
 **/


public class EIF {
    private static File eifFile = new File("F:\\DownLoad\\2.eif");

    private static final String raw = "";

    /*JPG 图片签名头，随后继续搜索知道找到ffd9两个字节*/
    private static final String JPG_TAG = "FFD8FF";
    /*GIF 图片签名头，但是gif是没有尾部标签的，虽然最后会以003b结尾但是中间可能出现003b，所以必须按照GIF的规则迭代读取字节信息直到不能迭代*/
    private static final String GIF_TAG = "47494638";//ascii "GIF"
    /*PNG图片签名头，随后查找尾部标志49454e44*/
    private static final String PNG_TAG = "89504E47";

    private static final String JPG_GIF_PNG_PATTERN = "(FFD8FF.*?FFD9|47494638.*003B|89504E47.*?49454E6082)";

//    private static final String s = "";


    public static void main(String[] args) throws IOException {
//        detectIllegalHexCharIndex(raw);
        exec();
//        System.out.println((1 << (0xF6 & 0x07) + 1) * 3);
//        String s = new BufferedReader(new InputStreamReader(new FileInputStream("image/a.txt"))).readLine();
//        convertHexStringToFile(s, "sssssss.png");
    }

    private static void detectIllegalHexCharIndex(String raw) {
        for (int i = 0; i < raw.length(); i++) {
            char c = raw.charAt(i);
            if (hexToBin(c) == -1)
                System.out.println("index: " + i + "  char: " + String.valueOf(new char[]{c}));
        }
    }

    private static void exec() throws IOException {
        File file = new File("image");
        boolean notExist = !file.exists();
        boolean notDirectory = !file.isDirectory();
        if (notExist || notDirectory) {
            file.mkdir();
        }
        System.out.println(file.getAbsolutePath());
        Pattern pattern = Pattern.compile(JPG_GIF_PNG_PATTERN);

        System.out.println(file2HexString(eifFile).equals(convertToHex(eifFile)));

        String eifHexString = convertToHex(eifFile);
        Matcher matcher = pattern.matcher(eifHexString);
        int count = 0;
        while (matcher.find()) {
            String fileItemByteHexString = matcher.group();
//            System.out.println(fileItemByteHexString);
            String suffix = fileSuffix(fileItemByteHexString);
            convertHexStringToFile(fileItemByteHexString, "" + (count + 1) + "." + suffix);
            count++;
            if (count > 10)
                break;
        }
    }

    private static String fileSuffix(String fileHexString) {
        if (fileHexString.indexOf(GIF_TAG) == 0)
            return "gif";
        if (fileHexString.indexOf(PNG_TAG) == 0)
            return "png";
        return "jpg";
    }

    private static String file2HexString(File eifFile) throws IOException {
        StringBuffer stringBuffer = new StringBuffer();
        byte[] buffer = new byte[Math.toIntExact(eifFile.length())];
        FileInputStream fos = new FileInputStream(eifFile);
        fos.read(buffer);
        for (int i = 0; i < buffer.length; i++) {
            stringBuffer.append(Integer.toHexString(buffer[i] & 0xFF));
        }
        return stringBuffer.toString();
    }

    private static int hexToBin(char ch) {
        if ('0' <= ch && ch <= '9') {
            return ch - '0';
        }
        if ('A' <= ch && ch <= 'F') {
            return ch - 'A' + 10;
        }
        if ('a' <= ch && ch <= 'f') {
            return ch - 'a' + 10;
        }
        return -1;
    }

    public static String convertToHex(File file) throws IOException {
        InputStream is = new FileInputStream(file);
        int bytesCounter = 0;
        int value = 0;
        StringBuilder sbHex = new StringBuilder();
        StringBuilder sbText = new StringBuilder();
        StringBuilder sbResult = new StringBuilder();
        while ((value = is.read()) != -1) {
            sbHex.append(String.format("%02X", value));
            if (bytesCounter == 15) {
                sbResult.append(sbHex);
                sbHex.setLength(0);
                sbText.setLength(0);
                bytesCounter = 0;
            } else {
                bytesCounter++;
            }
        }
        sbResult.append(sbHex);

        is.close();

        return sbResult.toString().trim();
    }

    private static void convertHexStringToFile(String source, String fileName) {
        if (source == null || source.isEmpty())
            return;
        System.out.println(source);
        byte[] bytes = hexStringToByteArray(source);
        try {
            File file = new File("image/" + fileName);
            if (!file.exists())
                file.createNewFile();
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bytes);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        if (s.length() % 2 != 0) {
            System.out.println(s);
            return null;
        }
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }
}
